<!doctype html><html lang="zh"><head><meta charset="utf-8"><meta name="generator" content="Hexo 4.2.0"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"><meta><meta name="keywords" content="null"><meta name="description" content="技术与生活缺一不可✔"><meta name="author" content="Wxperia 🛠"><title>分类: vue - 谢子乾</title><meta description="技术与生活缺一不可✔"><meta property="og:type" content="website"><meta property="og:title" content="Wxperia"><meta property="og:url" content="https://wxperia.github.io/"><meta property="og:site_name" content="子乾的个人博客"><meta property="og:description" content="技术与生活缺一不可✔"><meta property="og:locale" content="zh_CN"><meta property="article:author" content="Wxperia 🛠"><meta property="twitter:card" content="summary"><meta property="twitter:image" content="https://wxperia.github.io/img/avatar.png"><script type="application/ld+json">{"@context":"https://schema.org","@type":"BlogPosting","mainEntityOfPage":{"@type":"WebPage","@id":"https://Wxperia.github.io/"},"headline":"謝子乾 🐱‍🏍","image":["https://blog-status.oss-cn-beijing.aliyuncs.com/blog/img20200303171412.png"],"author":{"@type":"Person","name":"Wxperia 🛠"},"description":"技术与生活缺一不可✔"}</script><link rel="alternative" href="/atom.xml" title="谢子乾" type="application/atom+xml"><link rel="icon" href="https://blog-status.oss-cn-beijing.aliyuncs.com/blog/img20200303171412.png"><link rel="stylesheet" href="https://cdnjs.loli.net/ajax/libs/font-awesome/5.12.0/css/all.min.css"><link rel="stylesheet" href="https://fonts.loli.net/css?family=Ubuntu:400,600|Source+Code+Pro|Monda:300,300italic,400,400italic,700,700italic|Roboto Slab:300,300italic,400,400italic,700,700italic|Microsoft YaHei:300,300italic,400,400italic,700,700italic|PT Mono:300,300italic,400,400italic,700,700italic&amp;amp;subset=latin,latin-ext|Inconsolata|Itim|Lobster.css"><link rel="stylesheet" href="https://cdnjs.loli.net/ajax/libs/highlight.js/9.12.0/styles/atom-one-dark.min.css"><style>body>.footer,body>.navbar,body>.section{opacity:0}</style><script src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" defer></script><link rel="stylesheet" href="https://cdnjs.loli.net/ajax/libs/lightgallery/1.6.12/css/lightgallery.min.css"><link rel="stylesheet" href="https://cdnjs.loli.net/ajax/libs/justifiedGallery/3.7.0/css/justifiedGallery.min.css"><script src="https://cdnjs.loli.net/ajax/libs/pace/1.0.2/pace.min.js"></script><link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//css/style.min.css"><link rel="stylesheet" href="/css/e-style.css"><script src="https://cdnjs.loli.net/ajax/libs/jquery/3.3.1/jquery.min.js"></script><script src="https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//js/globalUtils.min.js"></script></head><body class="is-3-column has-navbar-fixed-top"><nav class="navbar navbar-main is-fixed-top"><div class="container"><div class="navbar-brand justify-content-center"><a class="navbar-item navbar-logo" href="/"><img src="https://blog-status.oss-cn-beijing.aliyuncs.com/blog/img20200303171412.png" alt="谢子乾" height="28"></a></div><div class="navbar-menu"><div class="navbar-start"><a class="navbar-item" href="/">首页</a><a class="navbar-item" href="/archives">归档</a><a class="navbar-item" href="/categories">分类</a><a class="navbar-item" href="/tags">标签</a><a class="navbar-item" href="/album">相册</a></div><div class="navbar-end"><a class="navbar-item" target="_blank" rel="noopener" title="Download on GitHub" href="https://github.com/removeif"><i class="fab fa-github"></i></a><a class="navbar-item search" title="搜索" href="javascript:;"><i class="fas fa-search"></i></a><a class="navbar-item" id="night-nav" title="Night Mode" href="javascript:;"><i class="fas fa-moon" id="night-icon"></i></a></div></div></div></nav><script type="text/javascript" src="https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//js/theme-setting.min.js"></script><section class="section"><div class="container"><div class="columns"><div class="column order-2 column-main is-8-tablet is-8-desktop is-6-widescreen"><div class="card"><div class="card-content"><nav class="breadcrumb" aria-label="breadcrumbs"><ul><li><a href="/categories">分类</a></li><li class="is-active"><a href="#" aria-current="page">vue</a></li></ul></nav></div></div><div class="card"><article class="card-content article" role="article"><div class="article-meta size-small is-uppercase level is-mobile"><div class="level-left"><i class="far fa-calendar-plus"> </i>2020-05-26  <a class="commentCountImg" href="/2020/05/26/Vue%E7%AE%80%E5%8D%95%E5%AE%9E%E8%B7%B5-vuex/#comment-container"><span class="display-none-class">b48a504dd4f881ae594ccabe98c5ba39</span><i class="far fa-comment-dots"></i> <span class="commentCount" id="b48a504dd4f881ae594ccabe98c5ba39">99+</span>  </a><span class="level-item"><i class="far fa-clock"> </i>2 分钟  <i class="fas fa-pencil-alt"> </i>0.3 k</span></div></div><h1 class="title is-3 is-size-4-mobile"><a class="link-muted" href="/2020/05/26/Vue%E7%AE%80%E5%8D%95%E5%AE%9E%E8%B7%B5-vuex/">【手写vuex】Vue简单实现-vuex</a></h1><div class="content"><h3 id="vuex-简单实现"><a href="#vuex-简单实现" class="headerlink" title="vuex 简单实现"></a>vuex 简单实现</h3><p><code>vuex</code> 实现不难，稍微要想一下的就是实现禁止直接修改state</p><p>稍微有一点经验的同学就能想到使用<code>Object.defineProperty</code></p><ul><li>实现vue插件形式使用</li><li>实现commit dispatch 方法</li><li>实现mutations getters actions 配置</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> Vue;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">install</span>(<span class="params">_vue</span>) </span>&#123;</span><br><span class="line">  Vue = _vue;</span><br><span class="line">  <span class="comment">/* 全局混入，在beforeCreate执行时，将$store挂载到全局。</span></span><br><span class="line"><span class="comment">  实现在所有组件调用this.$store */</span></span><br><span class="line">  Vue.mixin(&#123;</span><br><span class="line">    beforeCreate() &#123;</span><br><span class="line">        <span class="comment">/*只有在Vue实例初始化时有传入store才进行挂载，保证store只挂载一次， */</span></span><br><span class="line">      <span class="keyword">if</span> (<span class="keyword">this</span>.$options.store) &#123;</span><br><span class="line">        Vue.prototype.$store = <span class="keyword">this</span>.$options.store;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">store</span> </span>&#123;</span><br><span class="line">  <span class="keyword">constructor</span>(options = &#123;&#125;) &#123;</span><br><span class="line">    <span class="comment">// 这里再次利用Vue的特性，进行视图更新</span></span><br><span class="line">    <span class="keyword">this</span>.state = <span class="keyword">new</span> Vue(&#123;</span><br><span class="line">      data: options.state,</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="keyword">this</span>.mutations = options.mutations || &#123;&#125;;</span><br><span class="line">    <span class="keyword">this</span>.actions = options.actions || &#123;&#125;;</span><br><span class="line">    options.getters &amp;&amp; <span class="keyword">this</span>.initGetters(options.getters) || &#123;&#125;;</span><br><span class="line">  &#125;</span><br><span class="line">  commit = <span class="function">(<span class="params">type, arg</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="comment">//获取对应的mutations方法，返回commit方法</span></span><br><span class="line">    <span class="keyword">this</span>.mutations[type](<span class="keyword">this</span>.state, arg);</span><br><span class="line">  &#125;</span><br><span class="line">  dispatch = <span class="function">(<span class="params">type, arg</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="comment">//传入所有的commit用于修改state</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">this</span>.actions[type](&#123; <span class="attr">commit</span>: <span class="keyword">this</span>.commit &#125;, arg);</span><br><span class="line">  &#125;</span><br><span class="line">  initGetters = <span class="function">(<span class="params">getters</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="comment">//获取所有getter方法</span></span><br><span class="line">    <span class="built_in">Object</span>.keys(getters).forEach(<span class="function">(<span class="params">key</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">Object</span>.defineProperty(getters[key], key, &#123;</span><br><span class="line">          <span class="comment">//代理get方法获取到的值，保证不能被直接修改</span></span><br><span class="line">        <span class="keyword">get</span>: () =&gt; &#123;</span><br><span class="line">          <span class="keyword">return</span> getters[key](<span class="keyword">this</span>.state);</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;);</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><div class="index-category-tag"><div class="level-item"><i class="fas fa-folder-open has-text-grey"> </i><a class="article-more button is-small link-muted index-categories" href="/categories/vue/">vue</a></div>  <hr></div></article></div><div class="card"><article class="card-content article" role="article"><div class="article-meta size-small is-uppercase level is-mobile"><div class="level-left"><i class="far fa-calendar-plus"> </i>2020-05-26  <a class="commentCountImg" href="/2020/05/26/Vue%E7%AE%80%E5%8D%95%E5%AE%9E%E8%B7%B5-router/#comment-container"><span class="display-none-class">874259e454ba35f9a435d631469fbca7</span><i class="far fa-comment-dots"></i> <span class="commentCount" id="874259e454ba35f9a435d631469fbca7">99+</span>  </a><span class="level-item"><i class="far fa-clock"> </i>5 分钟  <i class="fas fa-pencil-alt"> </i>0.8 k</span></div></div><h1 class="title is-3 is-size-4-mobile"><a class="link-muted" href="/2020/05/26/Vue%E7%AE%80%E5%8D%95%E5%AE%9E%E8%B7%B5-router/">【vue源码阅读】Vue简单实现-router</a></h1><div class="content"><h3 id="vue-router的简单实现"><a href="#vue-router的简单实现" class="headerlink" title="vue-router的简单实现"></a>vue-router的简单实现</h3><ul><li>实现hash路由跳转</li><li>实现vue插件形式引用</li><li>router-link router-view</li></ul><h3 id="实现插件使用"><a href="#实现插件使用" class="headerlink" title="实现插件使用"></a>实现插件使用</h3><p>这点在vue官方文档中有提到，vue.use() 会调用传入对象的install方法，并且注入vue实例,所以只需要在导出的时候保证export default 的对象有install这个方法。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">let</span> Vue;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">mVueRouter</span> </span>&#123;</span><br><span class="line">        </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">mVueRouter.install = <span class="function"><span class="keyword">function</span>(<span class="params">_vue</span>)</span>&#123;</span><br><span class="line">      Vue = _vue <span class="comment">//获取vue实例，之后要用</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="实现页面根据hash地址变化而变化"><a href="#实现页面根据hash地址变化而变化" class="headerlink" title="实现页面根据hash地址变化而变化"></a>实现页面根据hash地址变化而变化</h3><p>利用Vue本身的响应式原理实现检测数据变化，解析传入的route配置</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line">  <span class="class"><span class="keyword">class</span> <span class="title">mVueRouter</span> </span>&#123;</span><br><span class="line">      <span class="keyword">constructor</span>(options) &#123;</span><br><span class="line">          <span class="comment">//获取用户配置</span></span><br><span class="line">          <span class="keyword">this</span>.$options = options;</span><br><span class="line">          <span class="comment">//创建一个路由path和route映射</span></span><br><span class="line">          <span class="keyword">this</span>.routeMap = &#123;&#125;;</span><br><span class="line">          <span class="comment">//将来当前路径current需要响应式</span></span><br><span class="line">          <span class="comment">//利用vue响应式原理可以做到这一点</span></span><br><span class="line">          <span class="keyword">this</span>.app = <span class="keyword">new</span> Vue(&#123;</span><br><span class="line">              data: &#123;</span><br><span class="line">                  current: <span class="string">"/"</span></span><br><span class="line">              &#125;</span><br><span class="line">          &#125;);</span><br><span class="line">      &#125;</span><br><span class="line">      init() &#123;</span><br><span class="line">          <span class="comment">//监听地址变化实时修改this.app.current的值</span></span><br><span class="line">          <span class="keyword">this</span>.bindEvent();</span><br><span class="line">          <span class="comment">//初始化路由地址配置</span></span><br><span class="line">          <span class="keyword">this</span>.createRouteMap(<span class="keyword">this</span>.$options);</span><br><span class="line">      &#125;</span><br><span class="line">      bindEvent() &#123;</span><br><span class="line">          <span class="built_in">window</span>.addEventListener(<span class="string">"load"</span>, <span class="keyword">this</span>.onHashChange.bind(<span class="keyword">this</span>),<span class="literal">false</span>);</span><br><span class="line">          <span class="built_in">window</span>.addEventListener(<span class="string">"hashchange"</span>, <span class="keyword">this</span>.onHashChange.bind(<span class="keyword">this</span>),<span class="literal">false</span>);</span><br><span class="line">      &#125;</span><br><span class="line">      onHashChange(e) &#123;</span><br><span class="line">          <span class="keyword">this</span>.app.current = <span class="built_in">window</span>.location.hash.slice(<span class="number">1</span>) || <span class="string">"/"</span>;</span><br><span class="line">      &#125;</span><br><span class="line">      createRouteMap(options) &#123;</span><br><span class="line">          options.routes.forEach(<span class="function"><span class="params">item</span> =&gt;</span> &#123;</span><br><span class="line">          <span class="comment">/* '/home': &#123;</span></span><br><span class="line"><span class="comment">              path:'/home',</span></span><br><span class="line"><span class="comment">              component: 'home'</span></span><br><span class="line"><span class="comment">          &#125; 大概就是这样子 */</span></span><br><span class="line">          <span class="keyword">this</span>.routeMap[item.path] = item;</span><br><span class="line">          &#125;);</span><br><span class="line">      &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="全局绑定router-link与router-view-组件"><a href="#全局绑定router-link与router-view-组件" class="headerlink" title="全局绑定router-link与router-view 组件"></a>全局绑定<code>router-link</code>与<code>router-view</code> 组件</h3><p>利用install时,获得的Vue实例来创建这两个组件</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">initComponent() &#123;</span><br><span class="line">    Vue.component(<span class="string">"router-view"</span>, &#123;</span><br><span class="line">      <span class="comment">//h函数方式实现</span></span><br><span class="line">      render: <span class="function"><span class="params">h</span> =&gt;</span>  &#123;</span><br><span class="line">        <span class="comment">//获取需要渲染的函数</span></span><br><span class="line">        <span class="keyword">let</span> component = <span class="keyword">this</span>.routeMap[<span class="keyword">this</span>.app.current].component;</span><br><span class="line">        <span class="keyword">return</span> h(component);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="comment">//react jsx方式实现 需要</span></span><br><span class="line">      <span class="comment">/*   render(h) &#123;</span></span><br><span class="line"><span class="comment">                return &lt;a href=&#123;this.to&#125;&gt;&#123;this.$slots.default&#125;&lt;/a&gt;</span></span><br><span class="line"><span class="comment">            &#125;  */</span></span><br><span class="line">    &#125;);</span><br><span class="line">    Vue.component(<span class="string">"router-link"</span>, &#123;</span><br><span class="line">      props: &#123;</span><br><span class="line">        to: <span class="built_in">String</span></span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="comment">//使用箭头函数 这里的this指向了 mVUeRouter</span></span><br><span class="line">      render(h) &#123;</span><br><span class="line">        <span class="keyword">return</span> h(</span><br><span class="line">          <span class="string">"a"</span>,</span><br><span class="line">          &#123;</span><br><span class="line">            attrs: &#123;</span><br><span class="line">              href: <span class="string">"#"</span> + <span class="keyword">this</span>.to</span><br><span class="line">            &#125;</span><br><span class="line">          &#125;,</span><br><span class="line">          <span class="keyword">this</span>.$slots.default</span><br><span class="line">        );</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="comment">//react jsx方式实现 需要</span></span><br><span class="line">      <span class="comment">/*   render(h) &#123;</span></span><br><span class="line"><span class="comment">                return &lt;a href=&#123;this.to&#125;&gt;&#123;this.$slots.default&#125;&lt;/a&gt;</span></span><br><span class="line"><span class="comment">            &#125;  */</span></span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure><p>完整代码</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> Vue;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">mVueRouter</span> </span>&#123;</span><br><span class="line">  <span class="keyword">constructor</span>(options) &#123;</span><br><span class="line">    <span class="keyword">this</span>.$options = options;</span><br><span class="line">    <span class="comment">//创建一个路由path和route映射</span></span><br><span class="line">    <span class="keyword">this</span>.routeMap = &#123;&#125;;</span><br><span class="line">    <span class="comment">//将来当前路径current需要响应式</span></span><br><span class="line">    <span class="comment">//利用vue响应式原理可以做到这一点</span></span><br><span class="line">    <span class="keyword">this</span>.app = <span class="keyword">new</span> Vue(&#123;</span><br><span class="line">      data: &#123;</span><br><span class="line">        current: <span class="string">"/"</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;</span><br><span class="line">  init() &#123;</span><br><span class="line">    <span class="comment">//解析路由配置</span></span><br><span class="line">    <span class="keyword">this</span>.bindEvent();</span><br><span class="line">    <span class="comment">//初始化路由地址配置</span></span><br><span class="line">    <span class="keyword">this</span>.createRouteMap(<span class="keyword">this</span>.$options);</span><br><span class="line">    <span class="comment">//全局挂载两个组件</span></span><br><span class="line">    <span class="keyword">this</span>.initComponent();</span><br><span class="line">  &#125;</span><br><span class="line">  createRouteMap(options) &#123;</span><br><span class="line">    options.routes.forEach(<span class="function"><span class="params">item</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="comment">// '/home':object &#123;&#125;</span></span><br><span class="line">      <span class="keyword">this</span>.routeMap[item.path] = item;</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;</span><br><span class="line">  bindEvent() &#123;</span><br><span class="line">    <span class="built_in">window</span>.addEventListener(<span class="string">"load"</span>, <span class="keyword">this</span>.onHashChange.bind(<span class="keyword">this</span>),<span class="literal">false</span>);</span><br><span class="line">    <span class="built_in">window</span>.addEventListener(<span class="string">"hashchange"</span>, <span class="keyword">this</span>.onHashChange.bind(<span class="keyword">this</span>),<span class="literal">false</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  onHashChange(e) &#123;</span><br><span class="line">    <span class="keyword">this</span>.app.current = <span class="built_in">window</span>.location.hash.slice(<span class="number">1</span>) || <span class="string">"/"</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  initComponent() &#123;</span><br><span class="line">    Vue.component(<span class="string">"router-view"</span>, &#123;</span><br><span class="line">      <span class="comment">//h函数方式实现</span></span><br><span class="line">      render: <span class="function"><span class="params">h</span> =&gt;</span>  &#123;</span><br><span class="line">        <span class="comment">//获取需要渲染的函数</span></span><br><span class="line">        <span class="keyword">let</span> component = <span class="keyword">this</span>.routeMap[<span class="keyword">this</span>.app.current].component;</span><br><span class="line">        <span class="keyword">return</span> h(component);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="comment">//react jsx方式实现 需要</span></span><br><span class="line">      <span class="comment">/*   render(h) &#123;</span></span><br><span class="line"><span class="comment">                return &lt;a href=&#123;this.to&#125;&gt;&#123;this.$slots.default&#125;&lt;/a&gt;</span></span><br><span class="line"><span class="comment">            &#125;  */</span></span><br><span class="line">    &#125;);</span><br><span class="line">    Vue.component(<span class="string">"router-link"</span>, &#123;</span><br><span class="line">      props: &#123;</span><br><span class="line">        to: <span class="built_in">String</span></span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="comment">//使用箭头函数 这里的this指向了 mVUeRouter</span></span><br><span class="line">      render(h) &#123;</span><br><span class="line">        <span class="keyword">return</span> h(</span><br><span class="line">          <span class="string">"a"</span>,</span><br><span class="line">          &#123;</span><br><span class="line">            attrs: &#123;</span><br><span class="line">              href: <span class="string">"#"</span> + <span class="keyword">this</span>.to</span><br><span class="line">            &#125;</span><br><span class="line">          &#125;,</span><br><span class="line">          <span class="keyword">this</span>.$slots.default</span><br><span class="line">        );</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="comment">//react jsx方式实现 需要</span></span><br><span class="line">      <span class="comment">/*   render(h) &#123;</span></span><br><span class="line"><span class="comment">                return &lt;a href=&#123;this.to&#125;&gt;&#123;this.$slots.default&#125;&lt;/a&gt;</span></span><br><span class="line"><span class="comment">            &#125;  */</span></span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">mVueRouter.install = <span class="function"><span class="keyword">function</span>(<span class="params">_vue</span>) </span>&#123;</span><br><span class="line">  <span class="comment">/* </span></span><br><span class="line"><span class="comment">          Vue.use()会调用这个install方法，将 _vue 实例传进来</span></span><br><span class="line"><span class="comment">      */</span></span><br><span class="line">  _vue.mixin(&#123;</span><br><span class="line">    <span class="comment">/* </span></span><br><span class="line"><span class="comment">      mixin 会在所有的组件在beforeCreate钩子中执行，</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line">    beforeCreate() &#123;</span><br><span class="line">      <span class="comment">//这里的代码将来会在初始化的时候被调用</span></span><br><span class="line">      <span class="comment">//将router挂载到prototype上</span></span><br><span class="line">      <span class="comment">//这里检查Vue实例是否已经有了对应的router实例保证router只挂载一次</span></span><br><span class="line">      <span class="keyword">if</span> (!<span class="keyword">this</span>.$options.router) &#123;</span><br><span class="line">        <span class="comment">/* </span></span><br><span class="line"><span class="comment">                    在new Vue(&#123;</span></span><br><span class="line"><span class="comment">                        router</span></span><br><span class="line"><span class="comment">                    &#125;)时起作用</span></span><br><span class="line"><span class="comment">                */</span></span><br><span class="line">        Vue.prototype.$router = <span class="keyword">this</span>.$options.router;</span><br><span class="line">        <span class="comment">//初始化组件</span></span><br><span class="line">        <span class="keyword">this</span>.$options.router.init();</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="comment">// Vue.prototype.$router = this.$options.router;</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;);</span><br><span class="line">  Vue = _vue;</span><br><span class="line">  <span class="comment">//在beforeCreate钩子前挂载router实例到根节点上</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> mVueRouter;</span><br></pre></td></tr></table></figure></div><div class="index-category-tag"><div class="level-item"><i class="fas fa-folder-open has-text-grey"> </i><a class="article-more button is-small link-muted index-categories" href="/categories/vue/">vue</a></div>  <hr></div></article></div><div class="card"><article class="card-content article" role="article"><div class="article-meta size-small is-uppercase level is-mobile"><div class="level-left"><i class="far fa-calendar-plus"> </i>2020-05-25  <a class="commentCountImg" href="/2020/05/25/Vue%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB-Event-js/#comment-container"><span class="display-none-class">d216899c08a67984c13c8f5dc96b8d77</span><i class="far fa-comment-dots"></i> <span class="commentCount" id="d216899c08a67984c13c8f5dc96b8d77">99+</span>  </a><span class="level-item"><i class="far fa-clock"> </i>5 分钟  <i class="fas fa-pencil-alt"> </i>0.7 k</span></div></div><h1 class="title is-3 is-size-4-mobile"><a class="link-muted" href="/2020/05/25/Vue%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB-Event-js/">【vue源码阅读注释】-Event.js</a></h1><div class="content"><h3 id="Vue中-on-与-emit的实现"><a href="#Vue中-on-与-emit的实现" class="headerlink" title="Vue中 $on 与 $emit的实现"></a>Vue中 $on 与 $emit的实现</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* @flow */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> &#123;</span><br><span class="line">    tip,</span><br><span class="line">    toArray,</span><br><span class="line">    hyphenate,</span><br><span class="line">    formatComponentName,</span><br><span class="line">    invokeWithErrorHandling</span><br><span class="line">&#125; <span class="keyword">from</span> <span class="string">'../util/index'</span></span><br><span class="line"><span class="keyword">import</span> &#123;</span><br><span class="line">    updateListeners</span><br><span class="line">&#125; <span class="keyword">from</span> <span class="string">'../vdom/helpers/index'</span></span><br><span class="line"><span class="comment">//在new vue 时执行这个方法将事件初始化</span></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">initEvents</span>(<span class="params">vm: Component</span>) </span>&#123;</span><br><span class="line">    vm._events = <span class="built_in">Object</span>.create(<span class="literal">null</span>)<span class="comment">//创建一个空对象，作为事件的容器</span></span><br><span class="line">    vm._hasHookEvent = <span class="literal">false</span></span><br><span class="line">    <span class="comment">// init parent attached events</span></span><br><span class="line">    <span class="keyword">const</span> listeners = vm.$options._parentListeners</span><br><span class="line">    <span class="keyword">if</span> (listeners) &#123;</span><br><span class="line">        updateComponentListeners(vm, listeners)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> target: any</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">add</span>(<span class="params">event, fn</span>) </span>&#123;</span><br><span class="line">    target.$on(event, fn)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">remove</span>(<span class="params">event, fn</span>) </span>&#123;</span><br><span class="line">    target.$off(event, fn)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createOnceHandler</span>(<span class="params">event, fn</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> _target = target</span><br><span class="line">    <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> <span class="title">onceHandler</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">const</span> res = fn.apply(<span class="literal">null</span>, <span class="built_in">arguments</span>)</span><br><span class="line">        <span class="keyword">if</span> (res !== <span class="literal">null</span>) &#123;</span><br><span class="line">            _target.$off(event, onceHandler)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">updateComponentListeners</span>(<span class="params"></span></span></span><br><span class="line"><span class="function"><span class="params">    vm: Component,</span></span></span><br><span class="line"><span class="function"><span class="params">    listeners: Object,</span></span></span><br><span class="line"><span class="function"><span class="params">    oldListeners: ? Object</span></span></span><br><span class="line"><span class="function"><span class="params"></span>) </span>&#123;</span><br><span class="line">    target = vm</span><br><span class="line">    updateListeners(listeners, oldListeners || &#123;&#125;, add, remove, createOnceHandler, vm)</span><br><span class="line">    target = <span class="literal">undefined</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//挂载 $on $once $emit $of</span></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">eventsMixin</span>(<span class="params">Vue: Class &lt; Component &gt; </span>) </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> hookRE = <span class="regexp">/^hook:/</span></span><br><span class="line">    Vue.prototype.$on = <span class="function"><span class="keyword">function</span>(<span class="params">event: string | Array &lt; string &gt; , fn: Function</span>): <span class="title">Component</span> </span>&#123;</span><br><span class="line">        <span class="keyword">const</span> vm: Component = <span class="keyword">this</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">Array</span>.isArray(event)) &#123;</span><br><span class="line">            <span class="comment">//支持数组传入，同时注册多个事件</span></span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>, l = event.length; i &lt; l; i++) &#123;</span><br><span class="line">                vm.$on(event[i], fn)</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">//检查是否存在这个方法名，每没有则创建一个空数组并且将方法push</span></span><br><span class="line">            (vm._events[event] || (vm._events[event] = [])).push(fn)</span><br><span class="line">            <span class="comment">// optimize hook:event cost by using a boolean flag marked at registration</span></span><br><span class="line">            <span class="comment">// instead of a hash lookup</span></span><br><span class="line">            <span class="keyword">if</span> (hookRE.test(event)) &#123;</span><br><span class="line">                vm._hasHookEvent = <span class="literal">true</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> vm</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    Vue.prototype.$once = <span class="function"><span class="keyword">function</span>(<span class="params">event: string, fn: Function</span>): <span class="title">Component</span> </span>&#123;</span><br><span class="line">        <span class="keyword">const</span> vm: Component = <span class="keyword">this</span></span><br><span class="line">        <span class="comment">//定义一个on方法。同时执行方法注销和执行</span></span><br><span class="line">        <span class="function"><span class="keyword">function</span> <span class="title">on</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">            <span class="comment">//注销这个方法</span></span><br><span class="line">            vm.$off(event, on)</span><br><span class="line">            <span class="comment">//执行fn,传入参数</span></span><br><span class="line">            fn.apply(vm, <span class="built_in">arguments</span>)</span><br><span class="line">        &#125;</span><br><span class="line">        on.fn = fn</span><br><span class="line">        vm.$on(event, on)</span><br><span class="line">        <span class="keyword">return</span> vm</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    Vue.prototype.$off = <span class="function"><span class="keyword">function</span>(<span class="params">event ? : string | Array &lt; string &gt; , fn ? : Function</span>): <span class="title">Component</span> </span>&#123;</span><br><span class="line">        <span class="keyword">const</span> vm: Component = <span class="keyword">this</span></span><br><span class="line">        <span class="comment">// all</span></span><br><span class="line">        <span class="keyword">if</span> (!<span class="built_in">arguments</span>.length) &#123;</span><br><span class="line">            <span class="comment">//不传参数直接清空事件容器，关闭所有事件</span></span><br><span class="line">            vm._events = <span class="built_in">Object</span>.create(<span class="literal">null</span>)</span><br><span class="line">            <span class="keyword">return</span> vm</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// array of events</span></span><br><span class="line">        <span class="comment">//兼容数组形式一次传入多个事件名</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">Array</span>.isArray(event)) &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>, l = event.length; i &lt; l; i++) &#123;</span><br><span class="line">                vm.$off(event[i], fn)</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> vm</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// specific event</span></span><br><span class="line">        <span class="comment">// 获取当前事件对应的方法是否为空，是则直接跳出方法</span></span><br><span class="line">        <span class="keyword">const</span> cbs = vm._events[event]</span><br><span class="line">        <span class="keyword">if</span> (!cbs) &#123;</span><br><span class="line">            <span class="keyword">return</span> vm</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 如果没有传入需要结束的方法则直接清空所有方法。</span></span><br><span class="line">        <span class="keyword">if</span> (!fn) &#123;</span><br><span class="line">            vm._events[event] = <span class="literal">null</span></span><br><span class="line">            <span class="keyword">return</span> vm</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// specific handler</span></span><br><span class="line">        <span class="comment">// 正常使用</span></span><br><span class="line">        <span class="keyword">let</span> cb</span><br><span class="line">        <span class="keyword">let</span> i = cbs.length</span><br><span class="line">        <span class="keyword">while</span> (i--) &#123;</span><br><span class="line">            cb = cbs[i]</span><br><span class="line">            <span class="comment">// 判断对应方法进行删除</span></span><br><span class="line">            <span class="keyword">if</span> (cb === fn || cb.fn === fn) &#123;</span><br><span class="line">                cbs.splice(i, <span class="number">1</span>)</span><br><span class="line">                <span class="comment">//删完break性能优化</span></span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> vm</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    Vue.prototype.$emit = <span class="function"><span class="keyword">function</span>(<span class="params">event: string</span>): <span class="title">Component</span> </span>&#123;</span><br><span class="line">        <span class="keyword">const</span> vm: Component = <span class="keyword">this</span></span><br><span class="line">        <span class="keyword">if</span> (process.env.NODE_ENV !== <span class="string">'production'</span>) &#123;</span><br><span class="line">            <span class="comment">//大小写报错</span></span><br><span class="line">            <span class="keyword">const</span> lowerCaseEvent = event.toLowerCase()</span><br><span class="line">            <span class="keyword">if</span> (lowerCaseEvent !== event &amp;&amp; vm._events[lowerCaseEvent]) &#123;</span><br><span class="line">                tip(</span><br><span class="line"><span class="string">`Event "<span class="subst">$&#123;lowerCaseEvent&#125;</span>" is emitted in component `</span> +</span><br><span class="line"><span class="string">`<span class="subst">$&#123;formatComponentName(vm)&#125;</span> but the handler is registered for "<span class="subst">$&#123;event&#125;</span>". `</span> +</span><br><span class="line"><span class="string">`Note that HTML attributes are case-insensitive and you cannot use `</span> +</span><br><span class="line"><span class="string">`v-on to listen to camelCase events when using in-DOM templates. `</span> +</span><br><span class="line"><span class="string">`You should probably use "<span class="subst">$&#123;hyphenate(event)&#125;</span>" instead of "<span class="subst">$&#123;event&#125;</span>".`</span> </span><br><span class="line">                )</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">let</span> cbs = vm._events[event]</span><br><span class="line">        <span class="keyword">if</span> (cbs) &#123;</span><br><span class="line">            cbs = cbs.length &gt; <span class="number">1</span> ? toArray(cbs) : cbs</span><br><span class="line">            <span class="keyword">const</span> args = toArray(<span class="built_in">arguments</span>, <span class="number">1</span>)</span><br><span class="line">            <span class="keyword">const</span> info = <span class="string">`event handler for "<span class="subst">$&#123;event&#125;</span>"`</span></span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>, l = cbs.length; i &lt; l; i++) &#123;</span><br><span class="line">                <span class="comment">//执行方法，并且捕获错误，兼容异步方法</span></span><br><span class="line">                invokeWithErrorHandling(cbs[i], vm, args, vm, info)</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> vm</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//拉到这了</span></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">invokeWithErrorHandling</span> (<span class="params"></span></span></span><br><span class="line"><span class="function"><span class="params">  handler: Function,</span></span></span><br><span class="line"><span class="function"><span class="params">  context: any,</span></span></span><br><span class="line"><span class="function"><span class="params">  args: null | any[],</span></span></span><br><span class="line"><span class="function"><span class="params">  vm: any,</span></span></span><br><span class="line"><span class="function"><span class="params">  info: string</span></span></span><br><span class="line"><span class="function"><span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">let</span> res</span><br><span class="line">  <span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="comment">//判断是否传参分情况执行</span></span><br><span class="line">    res = args ? handler.apply(context, args) : handler.call(context)</span><br><span class="line">    <span class="keyword">if</span> (res &amp;&amp; !res._isVue &amp;&amp; isPromise(res) &amp;&amp; !res._handled) &#123;</span><br><span class="line">      res.catch(<span class="function"><span class="params">e</span> =&gt;</span> handleError(e, vm, info + <span class="string">` (Promise/async)`</span>))</span><br><span class="line">      <span class="comment">// issue #9511</span></span><br><span class="line">      <span class="comment">// avoid catch triggering multiple times when nested calls</span></span><br><span class="line">      res._handled = <span class="literal">true</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">    handleError(e, vm, info)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> res</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><div class="index-category-tag"><div class="level-item"><i class="fas fa-folder-open has-text-grey"> </i><a class="article-more button is-small link-muted index-categories" href="/categories/vue/">vue</a></div>  <hr></div></article></div><div class="card"><article class="card-content article" role="article"><div class="article-meta size-small is-uppercase level is-mobile"><div class="level-left"><i class="far fa-calendar-plus"> </i>2020-05-14  <a class="commentCountImg" href="/2020/05/14/Vue%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB-new%20Vue()/#comment-container"><span class="display-none-class">0efd3f721988ca51c98d29e70b138b32</span><i class="far fa-comment-dots"></i> <span class="commentCount" id="0efd3f721988ca51c98d29e70b138b32">99+</span>  </a><span class="level-item"><i class="far fa-clock"> </i>8 分钟  <i class="fas fa-pencil-alt"> </i>1.2 k</span></div></div><h1 class="title is-3 is-size-4-mobile"><a class="link-muted" href="/2020/05/14/Vue%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB-new%20Vue()/">【vue源码阅读注释】</a></h1><div class="content"><h3 id="水平有限，好记性不如烂笔头。"><a href="#水平有限，好记性不如烂笔头。" class="headerlink" title="水平有限，好记性不如烂笔头。"></a>水平有限，好记性不如烂笔头。</h3><pre><code>基于 `vue2.6.11` 版本的源码,我也不知道为什么要写这篇博客,可能是因为一些视频里讲的不太清楚吧，自己也想记录下。</code></pre><h3 id="目录结构"><a href="#目录结构" class="headerlink" title="目录结构"></a>目录结构</h3><ul><li><p>src</p><ul><li><p><code>compiler</code> 编译相关</p></li><li><p><code>core</code> 核心部分</p></li><li><p><code>platforms</code> 平台兼容</p></li><li><p><code>server</code> ssr服务端渲染</p></li><li><p><code>sfc</code> vue解析</p></li><li><p><code>shared</code> 工具类等公共代码</p></li></ul></li></ul><h3 id="new-Vue"><a href="#new-Vue" class="headerlink" title="new Vue({})"></a>new Vue({})</h3><p><code>Vue</code> 定义在 <code>src/core/instance/index.js</code> 中</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//这里使用Es5的类的实现方式</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Vue</span>(<span class="params">options</span>) </span>&#123;</span><br><span class="line">    <span class="comment">//这里用来保证用户一定是用new关键字来使用这个类的。</span></span><br><span class="line">    <span class="keyword">if</span> (process.env.NODE_ENV !== <span class="string">'production'</span> &amp;&amp;</span><br><span class="line">        !(<span class="keyword">this</span> <span class="keyword">instanceof</span> Vue)</span><br><span class="line">    ) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> Vue(option) <span class="comment">//这行代码是我加的，我不知道为什么vue的作者不这样写，这样就能保证用户一定是用new关键字来初始化的</span></span><br><span class="line">        warn(<span class="string">'Vue is a constructor and should be called with the `new` keyword'</span>)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//这里就开始向这个实例挂载各种属性和方法了</span></span><br><span class="line">    <span class="keyword">this</span>._init(options)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>Vue</code> 实例化之后，调用了 <code>Vue._init()</code> 这个方法定义在 <code>src/core/instance/init.js</code></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line">Vue.prototype._init = <span class="function"><span class="keyword">function</span>(<span class="params">options ? : Object</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> vm: Component = <span class="keyword">this</span> <span class="comment">//this.指向刚刚的Vue实例</span></span><br><span class="line">    <span class="comment">// a uid</span></span><br><span class="line">    vm._uid = uid++ <span class="comment">//这里给每个创建的实例加一个uid</span></span><br><span class="line">    <span class="comment">//下面这一段，我看不懂到底要干嘛可能是编译相关？</span></span><br><span class="line">    <span class="keyword">let</span> startTag, endTag</span><br><span class="line">    <span class="comment">/* istanbul ignore if */</span></span><br><span class="line">    <span class="keyword">if</span> (process.env.NODE_ENV !== <span class="string">'production'</span> &amp;&amp; config.performance &amp;&amp; mark) &#123;</span><br><span class="line">        startTag = <span class="string">`vue-perf-start:<span class="subst">$&#123;vm._uid&#125;</span>`</span> </span><br><span class="line">        endTag = <span class="string">`vue-perf-end:<span class="subst">$&#123;vm._uid&#125;</span>`</span> </span><br><span class="line">        mark(startTag)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// a flag to avoid this being observed</span></span><br><span class="line">    vm._isVue = <span class="literal">true</span></span><br><span class="line">    <span class="comment">// merge options</span></span><br><span class="line">    <span class="comment">//合并options 也就是平时vue文件中export default &#123;&#125; 的内容这样就能实现使用this.xxx直接调用各种属性方法。并且针对不同的组件使用不同的合并策略</span></span><br><span class="line">    <span class="keyword">if</span> (options &amp;&amp; options._isComponent) &#123;</span><br><span class="line">        <span class="comment">// optimize internal component instantiation</span></span><br><span class="line">        <span class="comment">// since dynamic options merging is pretty slow, and none of the</span></span><br><span class="line">        <span class="comment">// internal component options needs special treatment.</span></span><br><span class="line"></span><br><span class="line">        initInternalComponent(vm, options)</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        vm.$options = mergeOptions(</span><br><span class="line">            resolveConstructorOptions(vm.constructor),</span><br><span class="line">            options || &#123;&#125;,</span><br><span class="line">            vm</span><br><span class="line">        )</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">/* istanbul ignore else */</span></span><br><span class="line">    <span class="keyword">if</span> (process.env.NODE_ENV !== <span class="string">'production'</span>) &#123;</span><br><span class="line">        initProxy(vm)</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        vm._renderProxy = vm</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// expose real self</span></span><br><span class="line">    vm._self = vm</span><br><span class="line">    <span class="comment">//各种全局方法的初始化</span></span><br><span class="line">    initLifecycle(vm)</span><br><span class="line">    initEvents(vm)</span><br><span class="line">    initRender(vm)</span><br><span class="line">    callHook(vm, <span class="string">'beforeCreate'</span>)</span><br><span class="line">    initInjections(vm) <span class="comment">// resolve injections before data/props</span></span><br><span class="line">    initState(vm) <span class="comment">//挂载你的data数据下面详细讲下这里</span></span><br><span class="line">    initProvide(vm) <span class="comment">// resolve provide after data/props</span></span><br><span class="line">    callHook(vm, <span class="string">'created'</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* istanbul ignore if */</span></span><br><span class="line">    <span class="keyword">if</span> (process.env.NODE_ENV !== <span class="string">'production'</span> &amp;&amp; config.performance &amp;&amp; mark) &#123;</span><br><span class="line">        vm._name = formatComponentName(vm, <span class="literal">false</span>)</span><br><span class="line">        mark(endTag)</span><br><span class="line">        measure( <span class="string">`vue <span class="subst">$&#123;vm._name&#125;</span> init`</span> , startTag, endTag)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (vm.$options.el) &#123;</span><br><span class="line">        <span class="comment">//挂载到dom,这时候界面就渲染出来了</span></span><br><span class="line">        vm.$mount(vm.$options.el)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>Vue</code> 这里我们先看下，为什么能直接用 <code>this.xxx</code> 来调用 <code>data</code> , <code>methods</code> 中的各种属性方法。<br>这个给 <code>src\core\instance\state.js</code></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">initState</span>(<span class="params">vm: Component</span>) </span>&#123;</span><br><span class="line">    vm._watchers = []</span><br><span class="line">    <span class="keyword">const</span> opts = vm.$options</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (opts.props) initProps(vm, opts.props) <span class="comment">//如果定义了props,就初始化props</span></span><br><span class="line">    <span class="keyword">if</span> (opts.methods) initMethods(vm, opts.methods) <span class="comment">//如果定义了methods就初始化methods</span></span><br><span class="line">    <span class="keyword">if</span> (opts.data) &#123;</span><br><span class="line">        <span class="comment">//这个方法就是罪魁祸首，我们康康他</span></span><br><span class="line">        initData(vm)</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        observe(vm._data = &#123;&#125;, <span class="literal">true</span> <span class="comment">/* asRootData */</span> )</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (opts.computed) initComputed(vm, opts.computed)</span><br><span class="line">    <span class="keyword">if</span> (opts.watch &amp;&amp; opts.watch !== nativeWatch) &#123;</span><br><span class="line">        initWatch(vm, opts.watch)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">initData</span>(<span class="params">vm: Component</span>) </span>&#123;</span><br><span class="line">    <span class="comment">//获取当前组件实例中的data</span></span><br><span class="line">    <span class="keyword">let</span> data = vm.$options.data</span><br><span class="line">    data = vm._data = <span class="keyword">typeof</span> data === <span class="string">'function'</span> ?</span><br><span class="line">        getData(data, vm) : <span class="comment">//这个方法会把data中的this指向修改为vm,并且将它传入data方法中</span></span><br><span class="line">        data || &#123;&#125;</span><br><span class="line">    <span class="comment">//判断他是否是一个普通对象，</span></span><br><span class="line">    <span class="comment">//isPlainObject这里大概是这样实现的 Object.prototype.toString.call(data) === '[object] [Object]'如果不是就要给你一个警告了</span></span><br><span class="line">    <span class="keyword">if</span> (!isPlainObject(data)) &#123;</span><br><span class="line">        data = &#123;&#125;</span><br><span class="line">        process.env.NODE_ENV !== <span class="string">'production'</span> &amp;&amp; warn(</span><br><span class="line">            <span class="string">'data functions should return an object:\n'</span> +</span><br><span class="line">            <span class="string">'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function'</span>,</span><br><span class="line">            vm</span><br><span class="line">        )</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// proxy data on instance</span></span><br><span class="line">    <span class="keyword">const</span> keys = <span class="built_in">Object</span>.keys(data) <span class="comment">//获取data中的属性名</span></span><br><span class="line">    <span class="keyword">const</span> props = vm.$options.props</span><br><span class="line">    <span class="keyword">const</span> methods = vm.$options.methods</span><br><span class="line">    <span class="keyword">let</span> i = keys.length</span><br><span class="line">    <span class="keyword">while</span> (i--) &#123; <span class="comment">//遍历属性，我也不知道为什么不用 for(let key in data)maybe这样性能更好？</span></span><br><span class="line">        <span class="keyword">const</span> key = keys[i]</span><br><span class="line">        <span class="comment">//判断是否在前面初始化的props 或者 methods中是否有重复定义的属性</span></span><br><span class="line">        <span class="keyword">if</span> (process.env.NODE_ENV !== <span class="string">'production'</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (methods &amp;&amp; hasOwn(methods, key)) &#123;</span><br><span class="line">                warn(</span><br><span class="line"><span class="string">`Method "<span class="subst">$&#123;key&#125;</span>" has already been defined as a data property.`</span> ,</span><br><span class="line">                    vm</span><br><span class="line">                )</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (props &amp;&amp; hasOwn(props, key)) &#123;</span><br><span class="line">            process.env.NODE_ENV !== <span class="string">'production'</span> &amp;&amp; warn(</span><br><span class="line"><span class="string">`The data property "<span class="subst">$&#123;key&#125;</span>" is already declared as a prop. `</span> +</span><br><span class="line"><span class="string">`Use prop default value instead.`</span> ,</span><br><span class="line">                vm</span><br><span class="line">            )</span><br><span class="line">            <span class="comment">//这是给自己做判断呢吧</span></span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (!isReserved(key)) &#123;</span><br><span class="line">            <span class="comment">//代理vm的get/set方法，让他从_data中获取对应的数据</span></span><br><span class="line">            proxy(vm, <span class="string">`_data`</span> , key)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// observe data</span></span><br><span class="line">    observe(data, <span class="literal">true</span> <span class="comment">/* asRootData */</span> )</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">proxy</span>(<span class="params">target: Object, sourceKey: string, key: string</span>) </span>&#123;</span><br><span class="line">    sharedPropertyDefinition.get = <span class="function"><span class="keyword">function</span> <span class="title">proxyGetter</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="comment">// 相当于 vm[sourseKey][key]</span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>[sourceKey][key]</span><br><span class="line">    &#125;</span><br><span class="line">    sharedPropertyDefinition.set = <span class="function"><span class="keyword">function</span> <span class="title">proxySetter</span>(<span class="params">val</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>[sourceKey][key] = val</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//看到这里，我有点忘记defineProperty是用来干嘛的，然后就取去查了文档</span></span><br><span class="line">    <span class="comment">//https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty</span></span><br><span class="line">    <span class="comment">//Object.defineProperty(obj, prop, descriptor)</span></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">    obj 要定义属性的对象。</span></span><br><span class="line"><span class="comment">    prop</span></span><br><span class="line"><span class="comment">    要定义或修改的属性的名称或 Symbol 。</span></span><br><span class="line"><span class="comment">    descriptor</span></span><br><span class="line"><span class="comment">    要定义或修改的属性描述符。 */</span></span><br><span class="line">    <span class="built_in">Object</span>.defineProperty(target, key, sharedPropertyDefinition)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div><div class="index-category-tag"><div class="level-item"><i class="fas fa-folder-open has-text-grey"> </i><a class="article-more button is-small link-muted index-categories" href="/categories/vue/">vue</a></div>  <hr></div></article></div></div><div class="column column-left is-4-tablet is-4-desktop is-3-widescreen order-1 is-sticky"><div class="card widget"><div class="card-content"><nav class="level"><div class="level-item has-text-centered flex-shrink-1"><div><figure class="image is-128x128 mx-auto mb-2"><img class="is-rounded" src="https://blog-status.oss-cn-beijing.aliyuncs.com/blog/img20200303171412.png" alt="Wxperia🚀"></figure><p class="title is-size-4 is-block line-height-inherit">Wxperia🚀</p><p class="is-size-6 is-block">江湖中迷走</p><p class="is-size-6 is-flex justify-content-center"><i class="fas fa-map-marker-alt mr-1"></i><span>广州🍵</span></p></div></div></nav><nav class="level is-mobile"><div class="level-item has-text-centered is-marginless"><div><p class="heading">文章</p><a href="/archives"><p class="title">46</p></a></div></div><div class="level-item has-text-centered is-marginless"><div><p class="heading">分类</p><a href="/categories"><p class="title">24</p></a></div></div><div class="level-item has-text-centered is-marginless"><div><p class="heading">标签</p><a href="/tags"><p class="title">35</p></a></div></div></nav><div class="level"><a class="level-item button is-primary is-rounded" href="/" target="_blank" rel="noopener">关注我</a></div><div class="level is-mobile"><a class="level-item button is-transparent is-white is-marginless" target="_blank" rel="noopener" title="Github" href="https://github.com/Wxperia"><i class="fab fa-github"></i></a><a class="level-item button is-transparent is-white is-marginless" target="_blank" rel="noopener" title="Weibo" href="https://weibo.com/u/3050419984"><i class="fab fa-weibo"></i></a><a class="level-item button is-transparent is-white is-marginless" target="_blank" rel="noopener" title="Email" href="/914827352@qq.com"><i class="fa fa-envelope"></i></a></div><div><hr><p id="hitokoto">:D 一言句子获取中...</p><script type="text/javascript" defer>function getYiyan(){$.getJSON("https://v1.hitokoto.cn/",function(o){o&&($("#hitokoto").html(""),$("#hitokoto").append("<strong style='color: #3273dc;'>"+o.hitokoto+"</strong><p>来源《"+o.from+"》</p><p>提供者-"+o.creator+"</p>"))})}$(function(){getYiyan(),$("#hitokoto").click(function(){getYiyan()})})</script></div></div></div><div class="column-right-shadow is-hidden-widescreen"></div></div><div class="column column-right is-4-tablet is-4-desktop is-3-widescreen is-hidden-touch is-hidden-desktop-only order-3"><div class="card widget"><div class="card-content"><h3 class="menu-label">最新文章</h3><article class="media"><div class="media-content size-small"><p><time datetime="2020-12-29T06:41:57.000Z">2020-12-29</time></p><p class="title is-6"><a class="link-muted" href="/2020/12/29/%E3%80%90vue%E3%80%91%E8%A7%A3%E8%80%A6%E6%A8%A1%E5%9D%97%E4%B9%8B%E9%97%B4%E7%9A%84%E8%AF%AD%E8%A8%80%E6%96%87%E4%BB%B6/">【vue】解耦模块之间的语言文件</a></p><p class="is-uppercase"></p></div></article><article class="media"><div class="media-content size-small"><p><time datetime="2020-12-28T01:46:47.000Z">2020-12-28</time></p><p class="title is-6"><a class="link-muted" href="/2020/12/28/%E3%80%90vue%E3%80%91%E6%97%A0%E7%BC%9Dtoken%E5%88%B7%E6%96%B0/">【vue】无缝token刷新</a></p><p class="is-uppercase"><i class="fas fa-folder-open has-text-grey"> </i><a class="link-muted" href="/categories/axios-token-refresh-token/">axios token refresh token</a></p></div></article><article class="media"><div class="media-content size-small"><p><time datetime="2020-12-24T15:56:05.000Z">2020-12-24</time></p><p class="title is-6"><a class="link-muted" href="/2020/12/24/HTML%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/">HTML理论知识</a></p><p class="is-uppercase"></p></div></article><article class="media"><div class="media-content size-small"><p><time datetime="2020-11-21T15:32:53.000Z">2020-11-21</time></p><p class="title is-6"><a class="link-muted" href="/2020/11/21/%E7%8A%80%E7%9A%AE%E6%BC%86%E5%99%A8%E7%9A%84%E4%B8%80%E8%88%AC%E5%88%B6%E4%BD%9C%E6%AD%A5%E9%AA%A4/">【花活】犀皮漆器的一般制作步骤</a></p><p class="is-uppercase"><i class="fas fa-folder-open has-text-grey"> </i><a class="link-muted" href="/categories/%E6%BC%86%E5%99%A8/">漆器</a></p></div></article><article class="media"><div class="media-content size-small"><p><time datetime="2020-11-01T04:08:22.000Z">2020-11-01</time></p><p class="title is-6"><a class="link-muted" href="/2020/11/01/%E3%80%90%E5%89%8D%E7%AB%AF%E3%80%91vue%E5%8A%A8%E6%80%81%E8%B7%AF%E7%94%B1%E5%AE%9E%E7%8E%B0-1/">【前端】vue权限管理</a></p><p class="is-uppercase"></p></div></article></div></div><div class="card widget"><div class="card-content"><div class="menu"><h3 class="menu-label">分类</h3><ul class="menu-list"><li><a class="level is-mobile is-marginless" href="/categories/Linux/"><span class="level-start"><span class="level-item">Linux</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/Tools/"><span class="level-start"><span class="level-item">Tools</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/Typescript/"><span class="level-start"><span class="level-item">Typescript</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/Vue/"><span class="level-start"><span class="level-item">Vue</span></span><span class="level-end"><span class="level-item tag">2</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/axios-token-refresh-token/"><span class="level-start"><span class="level-item">axios token refresh token</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/css/"><span class="level-start"><span class="level-item">css</span></span><span class="level-end"><span class="level-item tag">2</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/docker/"><span class="level-start"><span class="level-item">docker</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/hexo/"><span class="level-start"><span class="level-item">hexo</span></span><span class="level-end"><span class="level-item tag">4</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/hexo-Travis-github-action/"><span class="level-start"><span class="level-item">hexo Travis github-action</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><li><a class="level is-mobile is-marginless" href="/categories/jQuery/"><span class="level-start"><span class="level-item">jQuery</span></span><span class="level-end"><span class="level-item tag">1</span></span></a></li><a class="level is-mobile is-marginless" href="/categories/"><span class="level-start"><span class="level-item">查看全部&gt;&gt;</span></span></a></ul></div></div></div><div class="card widget"><div class="card-content"><div class="menu"><h3 class="menu-label">归档</h3><ul class="menu-list"><li><a class="level is-mobile is-marginless" href="/archives/2020/12/"><span class="level-start"><span class="level-item">十二月 2020</span></span><span class="level-end"><span class="level-item tag">3</span></span></a></li><li><a class="level is-mobile is-marginless" href="/archives/2020/11/"><span class="level-start"><span class="level-item">十一月 2020</span></span><span class="level-end"><span class="level-item tag">2</span></span></a></li><li><a class="level is-mobile is-marginless" href="/archives/2020/09/"><span class="level-start"><span class="level-item">九月 2020</span></span><span class="level-end"><span class="level-item tag">4</span></span></a></li><li><a class="level is-mobile is-marginless" href="/archives/2020/08/"><span class="level-start"><span class="level-item">八月 2020</span></span><span class="level-end"><span class="level-item tag">7</span></span></a></li><li><a class="level is-mobile is-marginless" href="/archives/2020/05/"><span class="level-start"><span class="level-item">五月 2020</span></span><span class="level-end"><span class="level-item tag">4</span></span></a></li><a class="level is-mobile is-marginless" href="/archives/"><span class="level-start"><span class="level-item">查看全部&gt;&gt;</span></span></a></ul></div></div></div><div class="card widget"><div class="card-content"><div class="menu"><h3 class="menu-label">标签</h3><div class="field is-grouped is-grouped-multiline"><div class="control"><a class="tags has-addons" href="/tags/ES6/"><span class="tag">ES6</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/metingJs/"><span class="tag">metingJs</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/JavaScript/"><span class="tag">JavaScript</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/LINUX/"><span class="tag">LINUX</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/OSS/"><span class="tag">OSS</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/Typescript/"><span class="tag">Typescript</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/aplayer/"><span class="tag">aplayer</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/cdn/"><span class="tag">cdn</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/es5/"><span class="tag">es5</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/funllscreen/"><span class="tag">funllscreen</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/git/"><span class="tag">git</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/github/"><span class="tag">github</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/github-page/"><span class="tag">github page</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/git%E5%A4%87%E4%BB%BD/"><span class="tag">git备份</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/google/"><span class="tag">google</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/javaScript/"><span class="tag">javaScript</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/markdown/"><span class="tag">markdown</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/tools-%E5%AE%9E%E7%94%A8%E5%B7%A5%E5%85%B7/"><span class="tag">+ tools + 实用工具</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/office2010/"><span class="tag">office2010</span><span class="tag is-grey-lightest">1</span></a></div><div class="control"><a class="tags has-addons" href="/tags/thymeleaft3/"><span class="tag">thymeleaft3</span><span class="tag is-grey-lightest">1</span></a></div></div><div class="field is-grouped is-grouped-multiline"><a class="tags has-addons" href="/tags/"><span class="tag">查看全部&gt;&gt;</span></a></div></div></div></div></div></div></div></section><footer class="footer"><div class="container"><div class="level"><div class="level-start"><a class="footer-logo is-block mb-2" href="/"><img src="https://blog-status.oss-cn-beijing.aliyuncs.com/blog/img20200303171412.png" alt="谢子乾" height="28"></a><p class="size-small"><span>&copy; 2020 谢子乾</span>    <br><span>© 版权说明：[本网站所有内容均收集于互联网或自己创作,<br>&nbsp;&nbsp;&nbsp;&nbsp;方便于网友与自己学习交流，如有侵权，请<a href="/message" target="_blank">留言</a>，立即处理]<br></span><span><span id="statistic-times">loading...</span><script>function createTime(n){var t=new Date(n);now.setTime(now.getTime()+250),days=(now-t)/1e3/60/60/24,dnum=Math.floor(days),hours=(now-t)/1e3/60/60-24*dnum,hnum=Math.floor(hours),1==String(hnum).length&&(hnum="0"+hnum),minutes=(now-t)/1e3/60-1440*dnum-60*hnum,mnum=Math.floor(minutes),1==String(mnum).length&&(mnum="0"+mnum),seconds=(now-t)/1e3-86400*dnum-3600*hnum-60*mnum,snum=Math.round(seconds),1==String(snum).length&&(snum="0"+snum),document.getElementById("statistic-times").innerHTML="❤️本站自 <strong>"+n.split(" ")[0].replace(/\//g,".")+"</strong> 已运行 <strong>"+dnum+"</strong> 天 <strong>"+hnum+"</strong> 小时 <strong>"+mnum+"</strong> 分 <strong>"+snum+"</strong> 秒！❤️"}var now=new Date;setInterval("createTime('2018/11/11 00:00:00')",250,"")</script><br></span></p><div class="size-small"><span>❤️感谢 <strong><span id="busuanzi_value_site_uv">99+</span></strong> 小伙伴的 <strong><span id="busuanzi_value_site_pv">99+</span></strong> 次光临！❤️</span></div><p></p></div><div class="level-end"><div class="field has-addons"><p class="control"><a class="button is-transparent is-large" target="_blank" rel="noopener" title="Creative Commons" href="https://creativecommons.org/"><i class="fab fa-creative-commons"></i></a></p><p class="control"><a class="button is-transparent is-large" target="_blank" rel="noopener" title="Attribution 4.0 International" href="https://creativecommons.org/licenses/by/4.0/"><i class="fab fa-creative-commons-by"></i></a></p><p class="control"><a class="button is-transparent is-large" target="_blank" rel="noopener" title="Download on GitHub" href="https://github.com/removeif"><i class="fab fa-github"></i></a></p></div><div class="sideMusic" id="myAdlayer"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/aplayer/1.10.1/APlayer.min.css" integrity="sha256-uqQQGnDcmRKvhKwc5Vm4XT1GQ2oV6t1U0NR2N9tV+BQ=" crossorigin="anonymous"><script src="https://cdnjs.cloudflare.com/ajax/libs/aplayer/1.10.1/APlayer.min.js" integrity="sha256-6Y7CJDaltoeNgk+ZftgCD9jLgmGv4xKUo8nQ0HgAwVo=" crossorigin="anonymous"></script><script src="https://cdn.jsdelivr.net/npm/meting@2/dist/Meting.min.js"></script><meting-js style="width:auto;height:2000px" type="playlist" auto="https://y.qq.com/n/yqq/playlist/7375663759.html#stat=y_new.profile.create_playlist.click&amp;dirid=24" theme="#2980b9" loop autoplay order="list" storagename="aplayer-setting" lrctype="0" list-max-height="400px" fixed="true" volume="0.7" list-folded="true"></meting-js></div></div></div></div></footer><script src="https://cdnjs.loli.net/ajax/libs/moment.js/2.22.2/moment-with-locales.min.js"></script><script>moment.locale("zh-CN")</script><script>var IcarusThemeSettings={site:{url:"https://wxperia.com",external_link:{enable:!0,exclude:[]}},article:{highlight:{clipboard:!0,fold:"unfolded"}}}</script><script src="https://cdnjs.loli.net/ajax/libs/clipboard.js/2.0.4/clipboard.min.js" defer></script><script src="https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//js/animation.min.js"></script><a id="back-to-top" title="回到顶端" href="javascript:;"><i class="fas fa-chevron-up"></i></a><script src="https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//js/back-to-top.min.js" defer></script><script src="https://cdnjs.loli.net/ajax/libs/lightgallery/1.6.12/js/lightgallery-all.min.js" defer></script><script src="https://cdnjs.loli.net/ajax/libs/justifiedGallery/3.7.0/js/jquery.justifiedGallery.min.js" defer></script><script src="https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//js/toc.min.js" defer></script><script src="https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//js/main.min.js" defer></script><script>$.getScript("https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//js/comment-issue-data.min.js",function(){loadIssueData("52c5fa5cd6ab2aba4c38","c153bf2fcf5d1e3784fcb161c2ca5702ca3bcaee","Wxperia","Wxperia.github.io",!1)})</script><link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//css/insight.min.css"><div class="searchbox ins-search"><div class="searchbox-container ins-search-container"><div class="searchbox-input-wrapper"><input class="searchbox-input ins-search-input" type="text" placeholder="想要查找什么..."><span class="searchbox-close ins-close ins-selectable"><i class="fa fa-times-circle"></i></span></div><div class="searchbox-result-wrapper ins-section-wrapper"><div class="ins-section-container"></div></div></div></div><script>window.INSIGHT_CONFIG={TRANSLATION:{POSTS:"文章",PAGES:"页面",CATEGORIES:"分类",TAGS:"标签",UNTITLED:"(无标题)"},CONTENT_URL:"https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//content.json"}</script><script src="https://cdn.jsdelivr.net/gh/wxperia/wxperia.github.io@latest//js/insight.min.js" defer></script></body></html>